/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package simplerecipes.model;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;


/**
 *
 * @author matamh0a
 */
public class Recipe implements PropertyChangeListener{
    String name;
    String preTime;
    String cookingTime;
    String readyIn;
    String source;
    String yield;
    String bakerNotes;
    double resizeFactor = 1.0;
    double actualFlourWeight;
    MeasurementType measurementType;
    
    String recipe;
    ArrayList<MesuredIngredient> ingredients;
    double toGramFactor = 1;
    Unit unit = Unit.g;
    
    protected double totalWeight;
    protected double totalCalories;
    protected int servings = 12;
    protected double flourWeight;
    protected double hydrationLevel;
    protected double caloriesPerServing;
    protected double weightPerServing = 0;
    protected double cost;
    protected double costPerServing;

    public static final String PROP_COSTPERSERVING = "costPerServing";
    public static final String PROP_COST = "cost";
    public static final String PROP_WEIGHTPERSERVING = "weightPerServing";
    public static final String PROP_CALORIESPERSERVING = "caloriesPerServing";
    public static final String PROP_FLOURWEIGHT = "flourWeight";
    public static final String PROP_HYDRATIONLEVEL = "hydrationLevel";
    public static final String PROP_SERVINGS = "servings";
    public static final String PROP_TOTALWEIGHT = "totalWeight";
    public static final String PROP_TOTALCALORIES = "totalCalories";

    public Recipe(String name) {
        this.name = name;
        ingredients = new ArrayList<MesuredIngredient>();
        measurementType = MeasurementType.QUANTITY;
    }

    public double getActualFlourWeight() {
        return actualFlourWeight;
    }

    public void setActualFlourWeight(double actualFlourWeight) {
//        System.out.println("AFW:" + actualFlourWeight);
        this.actualFlourWeight = actualFlourWeight;
        //update all the quantities
        MesuredIngredient ingd = null;
        double[] perct = new double[ingredients.size()];
        double[] w = new double[ingredients.size()];
        for(int i = 0; i < perct.length; i++) {
            perct[i] = ingredients.get(i).getPercentage();
            w[i] = ingredients.get(i).getIngredient().getWeight(ingredients.get(i).getUnit());
            ingredients.get(i).setUpdatePercentage(false);
//            System.out.println("i=" + i + ";%" + perct[i] + ";" + w[i]);
        }
        
        for(int i = 0; i < ingredients.size(); i++) {
            ingd = ingredients.get(i);
            ingd.setQuantity(actualFlourWeight * perct[i] / w[i]);
//            System.out.println("ii=" + i + ";%" + actualFlourWeight * perct[i] / 
//                    w[i]);
        }
        
        
        for(int i = 0; i < perct.length; i++) {
//            System.out.println("i=" + i);
            ingredients.get(i).setUpdatePercentage(true);
        }
    }

    public void setActualFlourWeight(double actualFlourWeight, boolean passive) {
        if(passive) {
            this.actualFlourWeight = actualFlourWeight;
        } else {
            setActualFlourWeight(actualFlourWeight);
        }
    }

    public String getBakerNotes() {
        return bakerNotes;
    }

    public void setBakerNotes(String bakerNotes) {
        this.bakerNotes = bakerNotes;
    }

    public String getCookingTime() {
        return cookingTime;
    }

    public void setCookingTime(String cookingTime) {
        this.cookingTime = cookingTime;
    }

    public ArrayList<MesuredIngredient> getIngredients() {
        return ingredients;
    }

    public void addIngredient(MesuredIngredient ingredient) {
        ingredients.add(ingredient);
        ingredient.addPropertyChangeListener(this);
    }
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPreTime() {
        return preTime;
    }

    public void setPreTime(String preTime) {
        this.preTime = preTime;
    }

    public String getReadyIn() {
        return readyIn;
    }

    public void setReadyIn(String readyIn) {
        this.readyIn = readyIn;
    }

    public String getRecipe() {
        return recipe;
    }

    public void setRecipe(String recipe) {
        this.recipe = recipe;
    }

    public double getResizeFactor() {
        return resizeFactor;
    }

    public void setResizeFactor(double resizeFactor) {
        this.resizeFactor = resizeFactor;
        
        //update all the quantities
        MesuredIngredient ingd = null;
        for(int i = 0; i < ingredients.size(); i++) {
            ingredients.get(i).setResizeFactor(resizeFactor);
        }
    }

    public int getServings() {
        return servings;
    }

    public void setServings(int servings) {
        double oldServings = this.servings;
        this.servings = servings;
        setCaloriesPerServing(totalCalories / servings);
        setWeightPerServing(totalWeight / servings);
        setCostPerServing(cost / servings);
        propertyChangeSupport.firePropertyChange(PROP_SERVINGS, oldServings, servings);
    }
    
    public String getSource() {
        return source;
    }

    public void setSource(String source) {
        this.source = source;
    }

    public String getYield() {
        return yield;
    }

    public void setYield(String yield) {
        this.yield = yield;
    }

    public double getHydrationLevel() {
        return hydrationLevel;
    }

    public void setHydrationLevel(double hydrationLevel) {
        double oldHydrationLevel = this.hydrationLevel;
        this.hydrationLevel = hydrationLevel;
        propertyChangeSupport.firePropertyChange(PROP_HYDRATIONLEVEL, oldHydrationLevel, hydrationLevel);
    }

    public double getFlourWeight() {
        return flourWeight;
    }

    public void setFlourWeight(double flourWeight) {
        double oldFlourWeight = this.flourWeight;
        this.flourWeight = flourWeight;
        propertyChangeSupport.firePropertyChange(PROP_FLOURWEIGHT, oldFlourWeight, flourWeight);
    }
    
     public double getTotalCalories() {
        return totalCalories;
    }
  
    public void setTotalCalories(double totalCalories) {
        double oldTotalCalories = this.totalCalories;
        this.totalCalories = totalCalories;
        propertyChangeSupport.firePropertyChange(PROP_TOTALCALORIES, oldTotalCalories, totalCalories);
    }

    public double getTotalWeight() {
        return totalWeight;
    }

    public void setTotalWeight(double totalWeight) {
        double oldTotalWeight = this.totalWeight;
        this.totalWeight = totalWeight;
        propertyChangeSupport.firePropertyChange(PROP_TOTALWEIGHT, oldTotalWeight, totalWeight);
    }

    public double getCaloriesPerServing() {
        return caloriesPerServing;
    }

    public void setCaloriesPerServing(double caloriesPerServing) {
        double oldCaloriesPerServing = this.caloriesPerServing;
        this.caloriesPerServing = caloriesPerServing;
        propertyChangeSupport.firePropertyChange(PROP_CALORIESPERSERVING, oldCaloriesPerServing, caloriesPerServing);
    }

    public MeasurementType getMeasurementType() {
        return measurementType;
    }

    public void setMeasurementType(MeasurementType measurementType) {
        this.measurementType = measurementType;
    }
 
    public void propertyChange(PropertyChangeEvent evt) {
        if(evt.getPropertyName().equals(MesuredIngredient.PROP_WEIGHT)
                || evt.getPropertyName().equals(MesuredIngredient.PROP_INCLUDED)) {
            double w = 0.0, f = 0.0, h = 0.0, c = 0.0;
            for(int i =0; i < ingredients.size(); i++) {
                if(!ingredients.get(i).isIncluded())
                    continue;
                
                w += ingredients.get(i).getWeight();
                if(ingredients.get(i).getIngredient().getType().equals(IngredientType.FLOUR))
                    f += ingredients.get(i).getWeight();
                if(ingredients.get(i).getIngredient().getType().equals(IngredientType.HYDRATION))
                    h += ingredients.get(i).getWeight();
                c += ingredients.get(i).getCost();
            }
            setTotalWeight(w);
            setFlourWeight(f);
            setCost(c);
            setHydrationLevel(h / f * 100);
            setWeightPerServing(totalWeight / servings);
            setCostPerServing(c / servings);
            //System.out.println("Total Weight: " + w);
            
            for(int i =0; i < ingredients.size(); i++) {
                ingredients.get(i).updatePercentage(f);
            }
        }
        
        if(evt.getPropertyName().equals(MesuredIngredient.PROP_CALORIES)
                || evt.getPropertyName().equals(MesuredIngredient.PROP_INCLUDED)) {
            double c = 0.0;
            for(int i =0; i < ingredients.size(); i++) {
                if(!ingredients.get(i).isIncluded())
                    continue;
                
                c += ingredients.get(i).getCalories();
            }
            setTotalCalories(c);
            setCaloriesPerServing(totalCalories / servings);
            //System.out.println("Total Calories: " + c);
        }
        
    }
    
    
    private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.addPropertyChangeListener(listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.removePropertyChangeListener(listener);
    }

    public void setUnit(Unit unit) {
        this.unit = unit;
        switch(unit) {
            case g:
                toGramFactor = 1.0;
                break;
            case kg:
                toGramFactor = Unit.KG_TO_G;
                break;
            case oz:
                toGramFactor = Unit.OZ_TO_G;
                break;
            case lb:
                toGramFactor = Unit.LB_TO_G;
                break;
        }
    }

    public double getToGramFactor() {
        return toGramFactor;
    }

    public Unit getUnit() {
        return unit;
    }
    
    public double getWeightPerServing() {
        return weightPerServing;
    }

    public void setWeightPerServing(double weightPerServing) {
        double oldWeightPerServing = this.weightPerServing;
        this.weightPerServing = weightPerServing;
        propertyChangeSupport.firePropertyChange(PROP_WEIGHTPERSERVING, oldWeightPerServing, weightPerServing);
    }

    public double getCost() {
        return cost;
    }

    public void setCost(double cost) {
        System.out.println("recipe.setCost(" + cost + ")");
        double oldCost = this.cost;
        this.cost = cost;
        propertyChangeSupport.firePropertyChange(PROP_COST, oldCost, cost);
    }
    
    public double getCostPerServing() {
        return costPerServing;
    }

    public void setCostPerServing(double costPerServing) {
        double oldCostPerServing = this.costPerServing;
        this.costPerServing = costPerServing;
        propertyChangeSupport.firePropertyChange(PROP_COSTPERSERVING, oldCostPerServing, costPerServing);
    }    
}
